package com.ruoyi.fantasy.utils;

import com.alibaba.fastjson.JSON;
import com.huanzhidadi.fantasy.common.constant.RedisConstants;
import org.apache.shiro.cache.CacheException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
public class RedisUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    private ZSetOperations<String, Object> zSetOperations = null;

    public RedisUtil() {

    }
    /**
     * 取出整个set的所有记录
     * @param key
     * @param expireSec
     * @return
     */
    public Set<Object> zgetAllMembers(String key, long expireSec) {
        zSetOperations = redisTemplate.opsForZSet();
        long now = System.currentTimeMillis();
        long tts = now - expireSec * 1000;
        //下标用-1才能表示最大值  score和count要用-inf和+inf
        //return zSetOperations.rangeByScore(key, tts+1, -1);
        return zSetOperations.rangeByScore(key, tts+1, Long.MAX_VALUE);
    }

    /**
     * 取出set中符合条件的指定数量的记录
     * @param key
     * @param expireSec
     * @return
     */
    public Set<Object> zgetMembersWithLimit(String key, long expireSec, long offset, long count) {
        zSetOperations = redisTemplate.opsForZSet();
        long now = System.currentTimeMillis();
        long tts = now - expireSec * 1000;
        //下标用-1才能表示最大值  score和count要用-inf和+inf
        //return zSetOperations.rangeByScore(key, tts+1, -1);
        return zSetOperations.rangeByScore(key, tts+1, Long.MAX_VALUE, offset, count);
    }

    /**
     * 分数从大到小取排行榜
     * @param key
     * @param start
     * @param stop
     * @return
     */
    public Set<Object> zreverange(String key, Integer start, Integer stop) {
        zSetOperations = redisTemplate.opsForZSet();
        return zSetOperations.reverseRange(key, start, stop);
    }

    /**
     * 获取指定对象的排名
     * @param key
     * @param member
     * @return
     */
    public Integer reverseRank(String key, Object member) {
        zSetOperations = redisTemplate.opsForZSet();
        return zSetOperations.reverseRank(key, member).intValue();
    }

    /**
     * 存入一条数据到sorted set    按时间排序
     * @param key
     * @param object
     */
    public boolean zset(String key, Object object){
        zSetOperations = redisTemplate.opsForZSet();
        long now = System.currentTimeMillis();
        return zSetOperations.add(key, object, now);
    }

    /**
     * 存入一条数据到sorted set    按分数排序
     * @param key
     * @param object
     */
    public boolean zsetWithScore(String key, Object object, long score){
        zSetOperations = redisTemplate.opsForZSet();
        return zSetOperations.add(key, object, score);
    }

    /**
     * 查看匹配数目
     * @param key
     * @param expireSec:过期时间 单位是秒
     * @return
     */
    public long zCount(String key, long expireSec){
        zSetOperations = redisTemplate.opsForZSet();
        long now = System.currentTimeMillis();
        long tts = now - expireSec * 1000;

        //下标用-1才能表示最大值  score和count要用-inf和+inf
        //return zSetOperations.count(key, tts+1, -1);

        return zSetOperations.count(key, tts+1, Long.MAX_VALUE);
    }

    /**
     * 删除一整个policyCache
     * @param zsetKey
     */
    public void removeCache(String zsetKey){
        redisTemplate.delete(zsetKey);
    }

    public void zsetDelMember(String key, Object value) {
        zSetOperations = redisTemplate.opsForZSet();
        zSetOperations.remove(key, value);
    }

    /**
     * 集合set中是否存在目标对象
     *
     * @param key
     * @param value
     * @return
     */
    public Boolean zsetScore(String key, Object value) {
        zSetOperations = redisTemplate.opsForZSet();
        if (zSetOperations.score(key, value) > 0) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * 缓存清理者
     * TODO 需要写个定时器调用
     */
    @SuppressWarnings("unchecked")
    public void cacheCleaner(){
        zSetOperations = redisTemplate.opsForZSet();
        Set<String> policyCacheKeys = redisTemplate.keys(RedisConstants.ZSET);
        if (policyCacheKeys==null || policyCacheKeys.isEmpty()) {
            return;
        }
        //移除过期数据
        long now = System.currentTimeMillis();
        long tts = now - RedisConstants.USER_ONLINE_EXPIRE_TIME * 1000;
        for (String key : policyCacheKeys) {
            zSetOperations.removeRangeByScore(key, 0, tts);
        }
    }


    /**
     * set集合获取
     *
     * @param key
     * @return
     */
    public Set<Object> getMembers(String key) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        return set.members(key);
    }

    /**
     * 集合set中是否存在目标对象
     *
     * @param key
     * @param value
     * @return
     */
    public Boolean isMember(String key, Object value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    public void addMember(String key, Object value) {
        redisTemplate.opsForSet().add(key, value);
    }

    public void addExMember(String key, String value, Integer time) {
        redisTemplate.opsForSet().add(key, value);
        setExpire(key, time);
    }

    public void delMember(String key, Object value) {
        redisTemplate.opsForSet().remove(key, value);
    }

    public Object scard(String key) {
        return redisTemplate.opsForSet().size(key);
    }

    public Set<String> smembers(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    public Long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    public void setExpire(String key, Integer time) {
        redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }

    /**
     * 存储简单数据类型
     * @param key
     * @param value
     */
    public void setValue(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 使用默认有效期和时间单位存储简单数据类型
     * @param key
     * @param value
     */
    public void setExValue(String key, Object value) {
        setExValue(key, value, RedisConstants.REDIS_DEFAULT_EXPIRE_TIME, RedisConstants.REDIS_DEFAULT_EXPIRE_TIMEUNIT);
    }

    /**
     * 使用指定有效期存储简单数据类型
     * @param key
     * @param value
     * @param time
     */
    public void setExValue(String key, Object value, long time) {
        setExValue(key, value, time, RedisConstants.REDIS_DEFAULT_EXPIRE_TIMEUNIT);
    }

    /**
     * 使用指定有效期和指定时间单位存储简单数据类型
     * @param key
     * @param value
     * @param time
     * @param timeUnit
     */
    public void setExValue(String key, Object value, long time, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, time, timeUnit);
    }

    /**
     * 获取简单数据类型
     * @param key
     * @return
     */
    public Object getValue(Object key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 递增
     * @param key
     */
    public void incr(String key) {
        redisTemplate.opsForValue().increment(key, 1);
    }
    /**
     * 递减
     * @param key
     */
    public void decr(String key) {
        redisTemplate.opsForValue().decrement(key, 1);
    }
    /**
     * 删除简单数据类型或实体类
     * @param key
     */
    public void delValue(String key) {
        redisTemplate.opsForValue().getOperations().delete(key);
    }

    /**
     * 实体类转换成string再进行操作
     *
     * @param key
     * @param value
     */
    public void setObjectValue(String key, Object value) {
        String jsonString = JSON.toJSONString(value);
        setValue(key, jsonString);
    }

    /**
     * 使用默认有效期存储实体类
     * @param key
     * @param value
     */
    public void setExObjectValue(String key, Object value) {
        String jsonString = JSON.toJSONString(value);
        setExValue(key, jsonString);
    }

    /**
     * 使用指定有效期存储实体类
     * @param key
     * @param value
     * @param time
     * @param timeUnit
     */
    public void setExObjectValue(String key, Object value, long time, TimeUnit timeUnit) {
        String jsonString = JSON.toJSONString(value);
        setExValue(key, jsonString, time, timeUnit);
    }

    /**
     * 获取实体类的JSONString
     * @param key
     * @return
     */
    public String getObjectString(String key) {
        return (String) redisTemplate.opsForValue().get(key);
    }

    /**
     * 从redis中获取map数据
     *
     * @param key
     * @return
     * @throws CacheException
     */
    public Map hmGet(String key) throws CacheException {

        try {
            return redisTemplate.opsForHash().entries(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 把map存到redis中
     *
     * @param key
     * @param map
     * @throws CacheException
     */
    public void hmPut(String key, Map map) throws CacheException {
        redisTemplate.opsForHash().putAll(key, map);
        //redisTemplate.opsForHash().getOperations().expire(key, 1, TimeUnit.HOURS);
    }

    public void hPut(String key, String hashKey, Object value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    public Object hGet(String key, String hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    public Long hDelete(String key, Object... hashKeys) {
        return redisTemplate.opsForHash().delete(key, hashKeys);
    }
    /**
     * 查询key是否存在
     *
     * @param redisKey
     * @return
     */
    public boolean isExist(String redisKey) {
        return redisTemplate.hasKey(redisKey);
    }

}
